﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using LeakView.common;
using LeakView.service;

namespace LeakView.view
{
    public partial class ViewGraphic : UserControl, Splashable
    {
        public Action<AjaxLeakInfo> LeakComfirmAction { get => this.tubeControl1.LeakComfirmAction; set => this.tubeControl1.LeakComfirmAction = value; }

        public ViewGraphic()
        {
            InitializeComponent();
        }

        private void ViewGraphic_Load(object sender, EventArgs e)
        {
            if(!CSharpUtilities.IsDesignMode())
            {
                this.tubeControl1.Tooltip = this.toolTip1;

                MainModule.current.LeakCreatedHandler += new Action<AjaxLeakInfo>(this.createLeak);
                MainModule.current.LeakDeletedHandler += new Action<AjaxLeakInfo>(this.deleteLeak);

                MainModule.current.GetCurrentLeaks().ForEach(n =>
                {
                    createLeak(n);
                });
            }
        }

        public void splash(bool flag)
        {
            if (MainModule.pair.Value.Valid)
            {
                this.labelPipeInfo.Text =
                    MainModule.pair.Value.Value.name +
                    " " +
                    MainModule.pair.Value.Value.length.ToString("F3") +
                    //PipeModal.ME.Distance + 
                    "千米";

                this.toolTip1.SetToolTip(this.pictureBox2, MainModule.pair.Value.Value.head.name);
                this.toolTip1.SetToolTip(this.pictureBox6, MainModule.pair.Value.Value.tail.name);
            }
            else
            {
                this.labelPipeInfo.Text = "服务器离线……";
                this.toolTip1.SetToolTip(this.pictureBox2, null);
                this.toolTip1.SetToolTip(this.pictureBox6, null);
            }

            if (MainModule.status.Value.Valid)
            {
                AjaxLeakPairStatus status = MainModule.status.Value.Value;

                // start
                if (!status.head)
                {
                    this.pictureBoxHead.Image = flag ? Properties.Resources.circle_normal : Properties.Resources.circle_offline;
                }
                else
                {
                    this.pictureBoxHead.Image = Properties.Resources.circle_normal;
                }

                // end
                if (!status.tail)
                {
                    this.pictureBoxTail.Image = flag ? Properties.Resources.circle_normal : Properties.Resources.circle_offline;
                }
                else
                {
                    this.pictureBoxTail.Image = Properties.Resources.circle_normal;
                }
            }
            else
            {
                this.pictureBoxHead.Image = flag ? Properties.Resources.circle_normal : Properties.Resources.circle_offline;
                this.pictureBoxTail.Image = flag ? Properties.Resources.circle_normal : Properties.Resources.circle_offline;
            }

            this.tubeControl1.splash(flag);

        }


        public void createLeak(AjaxLeakInfo leak)
        {
            if(this.InvokeRequired)
            {
                this.Invoke(new Action<AjaxLeakInfo>(tubeControl1.createLeak), new Object[] { leak });
            } 
            else
            {
                this.tubeControl1.createLeak(leak);
            }
        }

        public void deleteLeak(AjaxLeakInfo leak)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<AjaxLeakInfo>(tubeControl1.deleteLeak), new Object[] { leak });
            }
            else
            {
                this.tubeControl1.deleteLeak(leak);
            }
        }

    }


    public class TubeControl : Panel, Splashable
    {

        private Action<AjaxLeakInfo> leakComfirmAction = null;

        public Action<AjaxLeakInfo> LeakComfirmAction { get => leakComfirmAction; set => leakComfirmAction = value; }

        private readonly Dictionary<long, Needle> needles = new Dictionary<long, Needle>();

        private ToolTip tooltip = null;
        public ToolTip Tooltip { get => tooltip; set => tooltip = value; }


        private readonly ArrowPanel arrowPanel = new ArrowPanel();
        private readonly Timer arrowTimer = new Timer();
        private int arrowOffset = 0;

        public TubeControl()
        {
            this.BackgroundImage = Properties.Resources.pipe;
            this.BackgroundImageLayout = ImageLayout.Stretch;


            this.Controls.Add(arrowPanel);
            this.SetArrowPanel();
            arrowTimer.Interval = 50;
            arrowTimer.Tick += ArrowTimer_Tick;
            arrowTimer.Enabled = true;

            this.SizeChanged += TubeControl_SizeChanged;
        }

        private void ArrowTimer_Tick(object sender, EventArgs e)
        {
            arrowOffset += 2;
            SetArrowPanel();
        }

        private void SetArrowPanel()
        {
            if(arrowOffset > this.Width)
            {
                arrowOffset = 0;
            }

            this.arrowPanel.SetBounds(-this.Width + arrowOffset, 0, this.Width * 2, this.Height);
        }
        
        private void TubeControl_SizeChanged(object sender, EventArgs e)
        {
            SetArrowPanel();

            needles.Values.ToList().ForEach(n =>
            {
                layoutNeedle(n);
            });
        }

        public void splash(bool flag)
        {
            needles.Values.ToList().ForEach(n =>
            {
                n.splash(flag);
            });
        }

        public void createLeak(AjaxLeakInfo leak)
        {
            if (needles.ContainsKey(leak.id))
                return;

            Needle needle = new Needle
            {
                Leak = leak,
                TubeControl = this
            };

            layoutNeedle(needle);
            this.Controls.Add(needle);

            this.needles.Add(leak.id, needle);

            this.Tooltip.SetToolTip(needle, leak.location.ToString("F3") + "公里");
        }

        public void deleteLeak(AjaxLeakInfo leak)
        {
            if(needles.ContainsKey(leak.id))
            {
                Needle needle = needles[leak.id];
                this.Controls.Remove(needle);
                this.needles.Remove(leak.id);
                this.Tooltip.SetToolTip(needle, null);
            }
        }

        private void layoutNeedle(Needle needle)
        {
            int side = this.Height;

            int controlLength = this.Width - side;

            double pipeLength = 10.0;
            if (MainModule.pair.Value.Valid)
            {
                pipeLength = MainModule.pair.Value.Value.length;
            }

            double leakDistance = needle.Leak.location;

            double controlDistance = controlLength * leakDistance / pipeLength;

            if(controlDistance > controlLength)
            {
                controlDistance = controlLength;
            }

            int x = Convert.ToInt32(controlDistance);
            needle.SetBounds(x, 0, side, side);

        }

    }


    class Needle : PictureBox, Splashable
    {
        public static readonly Bitmap bm1 = Properties.Resources.needle;

        public static readonly Bitmap bm2 = ToGray(new Bitmap(bm1));

        private AjaxLeakInfo leak = null;

        public AjaxLeakInfo Leak { get => leak; set => leak = value; }
        
        private TubeControl tubeControl = null;
        public TubeControl TubeControl { get => tubeControl; set => tubeControl = value; }

        public static Bitmap ToGray(Bitmap bmp)
        {
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    //获取该点的像素的RGB的颜色
                    Color color = bmp.GetPixel(i, j);
                    //利用公式计算灰度值
                    int gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
                    Color newColor = Color.FromArgb(gray, gray, gray);
                    bmp.SetPixel(i, j, newColor);
                }
            }
            return bmp;
        }

        public Needle()
        {
            this.SizeMode = PictureBoxSizeMode.StretchImage;
            splash(true);

            this.MouseDoubleClick += Needle_MouseDoubleClick;
        }

        private void Needle_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.TubeControl.LeakComfirmAction?.Invoke(leak);
        }

        public void splash(bool flag)
        {
            this.Image = flag ? bm2 : bm1;
        }
    }

    public class ArrowPanel : Panel
    {
        public ArrowPanel()
        {
            this.BackgroundImage = MakeBackgroundImage();
            this.BackgroundImageLayout = ImageLayout.Stretch;
        }


        private Image MakeBackgroundImage()
        {
            var pipe = Properties.Resources.pipe;

            var width = pipe.Width * 2;
            var height = pipe.Height;

            Bitmap bitMap = new Bitmap(width, height);
            Graphics g1 = Graphics.FromImage(bitMap);
            g1.FillRectangle(Brushes.White, new Rectangle(0, 0, width, height));
            g1.DrawImage(pipe, 0, 0, pipe.Width, pipe.Height);
            g1.DrawImage(pipe, pipe.Width, 0, pipe.Width, pipe.Height);
            return bitMap;
        }

    }


}
